package com.cash.app.utils.extra.tools

import android.Manifest
import android.annotation.SuppressLint
import android.app.UiModeManager
import android.content.Context
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.Build
import android.provider.Settings
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.text.TextUtils
import androidx.core.app.ActivityCompat
import com.cash.app.constant.AppConstant.K_GA_ID
import com.cash.app.utils.SpUtils
import com.cash.app.utils.extra.ExtraInfoUtils
import com.cash.app.utils.extra.tools.OtherUtils.judgeSIMCount
import com.cash.app.utils.extra.model.SimCardData
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.util.UUID

object GeneralUtils {
    var gaid: String = ""

    fun isChekSelfPermission(permission: String): Boolean {
        if (ActivityCompat.checkSelfPermission(
                ExtraInfoUtils.getApp(), permission
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return true
        }
        return false
    }

    @get:SuppressLint("HardwareIds")
    val androidID: String
        get() {
            val id = Settings.Secure.getString(
                ExtraInfoUtils.getApp().getContentResolver(), Settings.Secure.ANDROID_ID
            )
            return id ?: ""
        }

    val networkOperatorName: String
        get() = telephonyManager.getNetworkOperatorName()

    val networkOperator: String
        get() = telephonyManager.getNetworkOperator()


    val mcc: String
        get() {
            val networkOperator: String = telephonyManager.getNetworkOperator()
            return if (!TextUtils.isEmpty(networkOperator)) {
                networkOperator.substring(0, 3)
            } else {
                ""
            }
        }

    val mnc: String
        get() {
            val networkOperator: String = telephonyManager.getNetworkOperator()
            return if (!TextUtils.isEmpty(networkOperator)) {
                networkOperator.substring(3)
            } else {
                ""
            }
        }

    val networkType: String?
        get() {
            if (isChekSelfPermission(Manifest.permission.ACCESS_NETWORK_STATE)) {
                return "NETWORK_NO"
            }
            if (isEthernet) {
                return "NETWORK_ETHERNET"
            }
            val cm: ConnectivityManager = ExtraInfoUtils.getApp()
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            if (cm == null) {
                return null
            }
            val info: NetworkInfo? = cm.getActiveNetworkInfo()
            if (info != null && info.isAvailable()) {
                if (info.getType() == ConnectivityManager.TYPE_WIFI) {
                    return "NETWORK_WIFI"
                } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) {
                    when (info.getSubtype()) {
                        TelephonyManager.NETWORK_TYPE_GSM, TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> return "NETWORK_2G"

                        TelephonyManager.NETWORK_TYPE_TD_SCDMA, TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> return "NETWORK_3G"

                        TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyManager.NETWORK_TYPE_LTE -> return "NETWORK_4G"

                        TelephonyManager.NETWORK_TYPE_NR -> return "NETWORK_5G"
                        else -> {
                            val subtypeName: String = info.getSubtypeName()
                            return if (subtypeName.equals(
                                    "TD-SCDMA", ignoreCase = true
                                ) || subtypeName.equals(
                                    "WCDMA", ignoreCase = true
                                ) || subtypeName.equals("CDMA2000", ignoreCase = true)
                            ) {
                                "NETWORK_3G"
                            } else {
                                "NETWORK_UNKNOWN"
                            }
                        }
                    }
                } else {
                    return "NETWORK_UNKNOWN"
                }
            }
            return "NETWORK_NO"
        }

    val phoneType: String
        get() {
            val phoneType: Int = telephonyManager.getPhoneType()
            when (phoneType) {
                TelephonyManager.PHONE_TYPE_NONE -> return "PHONE_TYPE_NONE"
                TelephonyManager.PHONE_TYPE_GSM -> return "PHONE_TYPE_GSM"
                TelephonyManager.PHONE_TYPE_CDMA -> return "PHONE_TYPE_CDMA"
                TelephonyManager.PHONE_TYPE_SIP -> return "PHONE_TYPE_SIP"
            }
            return ""
        }

    private val isEthernet: Boolean
        get() {
            val cm: ConnectivityManager = ExtraInfoUtils.getApp()
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            if (cm == null) return false
            val info: NetworkInfo =
                cm.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET) ?: return false
            val state: NetworkInfo.State = info.getState() ?: return false
            return state == NetworkInfo.State.CONNECTED || state == NetworkInfo.State.CONNECTING
        }


    fun getIMSI(subId: Int): String {
        val telephonyManager: TelephonyManager = telephonyManager // 取得相关系统服务
        var telephonyManagerClass: Class<*>? = null
        var imsi = ""
        try {
            telephonyManagerClass = Class.forName("android.telephony.TelephonyManager")
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                val method = telephonyManagerClass.getMethod(
                    "getSubscriberId", Int::class.javaPrimitiveType
                )
                imsi = method.invoke(telephonyManager, subId) as String
            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
                val method = telephonyManagerClass.getMethod(
                    "getSubscriberId", Long::class.javaPrimitiveType
                )
                imsi = method.invoke(telephonyManager, subId.toLong()) as String
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (imsi == null) {
            imsi = ""
        }
        return imsi
    }

    @get:SuppressLint("MissingPermission")
    val simCardInfo: SimCardData
        get() {
            val simCardData: SimCardData = SimCardData()
            simCardData.sim_count = judgeSIMCount
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                val mSubscriptionManager: SubscriptionManager = ExtraInfoUtils.getApp()
                    .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                var activeSubscriptionInfoList: List<SubscriptionInfo>? = null
                if (mSubscriptionManager != null) {
                    try {
                        activeSubscriptionInfoList =
                            mSubscriptionManager.getActiveSubscriptionInfoList()
                    } catch (ignored: Exception) {
                    }
                }
                if (activeSubscriptionInfoList != null && activeSubscriptionInfoList.size > 0) {
                    for (i in activeSubscriptionInfoList.indices) {
                        val subscriptionInfo: SubscriptionInfo = activeSubscriptionInfoList[i]
                        if (i == 0) {
                            simCardData.number1 = subscriptionInfo.getNumber()
                        } else {
                            simCardData.number2 = subscriptionInfo.getNumber()
                        }
                    }
                }
            }
            return simCardData
        }

    val meid: String
        get() = getImeiOrMeid(false)

    fun getImeiOrMeid(isImei: Boolean): String {
        if (isChekSelfPermission(Manifest.permission.READ_PHONE_STATE)) {
            return ""
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return ""
        }
        val tm: TelephonyManager = telephonyManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return if (isImei) {
                //getMinOne(tm.getImei(0), tm.getImei(1))
                getMinOne("", "")
            } else {
                //getMinOne(tm.getMeid(0), tm.getMeid(1))
                getMinOne("", "")
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val ids = getSystemPropertyByReflect(if (isImei) "ril.gsm.imei" else "ril.cdma.meid")
            if (!TextUtils.isEmpty(ids)) {
                val idArr = ids!!.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                return if (idArr.size == 2) {
                    getMinOne(
                        idArr[0], idArr[1]
                    )
                } else {
                    idArr[0]
                }
            }
            var id0: String = "" //tm.getDeviceId()
            var id1 = ""
            try {
                val method: Method =
                    tm.javaClass.getMethod("getDeviceId", Int::class.javaPrimitiveType)
                id1 = method.invoke(
                    tm, if (isImei) TelephonyManager.PHONE_TYPE_GSM
                    else TelephonyManager.PHONE_TYPE_CDMA
                ) as String
            } catch (e: NoSuchMethodException) {
                e.printStackTrace()
            } catch (e: IllegalAccessException) {
                e.printStackTrace()
            } catch (e: InvocationTargetException) {
                e.printStackTrace()
            }
            if (isImei) {
                if (id0 != null && id0.length < 15) {
                    id0 = ""
                }
                if (id1 != null && id1.length < 15) {
                    id1 = ""
                }
            } else {
                if (id0 != null && id0.length == 14) {
                    id0 = ""
                }
                if (id1 != null && id1.length == 14) {
                    id1 = ""
                }
            }
            return getMinOne(id0, id1)
        } else {
            val deviceId: String = "" //tm.getDeviceId()
            if (isImei) {
                if (deviceId != null && deviceId.length >= 15) {
                    return deviceId
                }
            } else {
                if (deviceId != null && deviceId.length == 14) {
                    return deviceId
                }
            }
        }
        return ""
    }

    private fun getMinOne(s0: String, s1: String): String {
        val empty0 = TextUtils.isEmpty(s0)
        val empty1 = TextUtils.isEmpty(s1)
        if (empty0 && empty1) return ""
        if (!empty0 && !empty1) {
            return if (s0.compareTo(s1) <= 0) {
                s0
            } else {
                s1
            }
        }
        if (!empty0) return s0
        return s1
    }

    private fun getSystemPropertyByReflect(key: String): String? {
        try {
            @SuppressLint("PrivateApi") val clz = Class.forName("android.os.SystemProperties")
            val getMethod = clz.getMethod(
                "get", String::class.java, String::class.java
            )
            return getMethod.invoke(clz, key, "") as String
        } catch (e: Exception) { /**/
        }
        return ""
    }


    val cidNumbers: String
        get() = ""

    //        try {
//            if (getTelephonyManager().getPhoneType() == PHONE_TYPE_GSM) {
//                if (ActivityCompat.checkSelfPermission(ExtraInfoUtils.getApp(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//                    return "";
//                }
//                final GsmCellLocation location = (GsmCellLocation) getTelephonyManager().getCellLocation();
//                if (location != null) {
//                    return String.valueOf(location.getCid());
//                }
//            }
//            return "";
//        }catch (Exception e){
//            return "";
//        }


    val localDNS: String?
        get() {
            var cmdProcess: Process? = null
            var reader: BufferedReader? = null
            var dnsIP: String? = ""
            try {
                cmdProcess = Runtime.getRuntime().exec("getprop net.dns1")
                reader = BufferedReader(InputStreamReader(cmdProcess.inputStream))
                dnsIP = reader.readLine()
                return dnsIP
            } catch (e: IOException) {
                return null
            } finally {
                try {
                    reader!!.close()
                } catch (e: IOException) {
                }
                cmdProcess!!.destroy()
            }
        }

    val uUids: String
        get() = UUID.randomUUID().toString()

    val myUUID: String
        get() {
            if (isChekSelfPermission(Manifest.permission.READ_PHONE_STATE)) {
                return ""
            }
            val tm: TelephonyManager = telephonyManager
            val tmDevice: String
            val tmSerial: String
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                tmDevice = ""
                tmSerial = ""
            } else {
                tmDevice = "" + "" // tm.getDeviceId()
                tmSerial = "" + "" // tm.getSimSerialNumber()
            }
            val deviceUuid = UUID(
                androidID.hashCode().toLong(),
                (tmDevice.hashCode().toLong() shl 32) or tmSerial.hashCode().toLong()
            )
            val uniqueId = deviceUuid.toString()
            return uniqueId
        }


    fun getIMEI(slotId: Int): String? {
        try {
            val manager: TelephonyManager = telephonyManager
            val method: Method =
                manager.javaClass.getMethod("getImei", Int::class.javaPrimitiveType)
            val imei = method.invoke(manager, slotId) as String
            return imei
        } catch (e: Exception) {
            return ""
        }
    }

    fun getGaid() {
        gaid = SpUtils.get(K_GA_ID, "")
    }

    val uiModeType: String
        get() {
            val mUiModeManager: UiModeManager =
                ExtraInfoUtils.getApp().getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
            val uiMode: Int = mUiModeManager.getCurrentModeType()
            return when (uiMode) {
                Configuration.UI_MODE_TYPE_UNDEFINED -> "UI_MODE_TYPE_UNDEFINED"
                Configuration.UI_MODE_TYPE_NORMAL -> "UI_MODE_TYPE_NORMAL"
                Configuration.UI_MODE_TYPE_DESK -> "UI_MODE_TYPE_DESK"
                Configuration.UI_MODE_TYPE_CAR -> "UI_MODE_TYPE_CAR"
                Configuration.UI_MODE_TYPE_TELEVISION -> "UI_MODE_TYPE_TELEVISION"
                Configuration.UI_MODE_TYPE_APPLIANCE -> "UI_MODE_TYPE_APPLIANCE"
                Configuration.UI_MODE_TYPE_WATCH -> "UI_MODE_TYPE_WATCH"
                Configuration.UI_MODE_TYPE_VR_HEADSET -> "UI_MODE_TYPE_VR_HEADSET"
                else -> uiMode.toString()
            }
        }

    private val telephonyManager: TelephonyManager
        get() = ExtraInfoUtils.getApp().getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
}